#ifndef OBJECT_HPP
#define OBJECT_HPP

#include <stdlib.h>

class DictObject;
class LambdaDef;
class Klass;

class Object {
private:
    Klass* _klass;

public:
    virtual void print() = 0;
    virtual Object* add(Object* o);
    virtual Object* mul(Object* o);
    virtual int compare(Object* o);

    bool is_int();
    bool is_char();
    bool is_native_func();
    
    void* operator new(size_t size);
    void set_klass(Klass* klass) { _klass = klass; }
};

class IntObject : public Object {
private:
    int _value;

public:
    IntObject(int v);

    int value() {
        return _value;
    }

    bool equal(IntObject* y);

    virtual Object* add(Object* r);
    virtual Object* mul(Object* r);

    IntObject* sub(IntObject* r);
    IntObject* div(IntObject* r);

    IntObject* bit_and(IntObject* r);
    IntObject* bit_or(IntObject* r);
    IntObject* bit_xor(IntObject* r);
    IntObject* lshift(IntObject* r);
    IntObject* rshift(IntObject* r);

    void print();
    int compare(Object* o);
};

class ClosureObject : public Object {
private:
    LambdaDef*  _lambda;
    DictObject* _env;

public:
    ClosureObject(LambdaDef* l, DictObject* e);

    LambdaDef* func_def() { return _lambda; }
    DictObject* env()     { return _env; }

    void print();
};

class UnitObject : public Object {
public:
    static IntObject* UnitValue;
};

class StringObject : public Object {
private:
    char* _value;
    int   _length;

public:
    StringObject(const char* v, int length);
    StringObject(const char* v);

    const char* value() { return _value; }
    void set_value(char* v) { _value = v; }

    int length() { return _length; }
    void set_length(int len) { _length = len; }

    void print();
    int compare(Object* o);

    virtual Object* add(Object* o);
    virtual Object* mul(Object* o);
};

class BoolObject : public Object {
public:
    static StringObject* TrueValue;
    static StringObject* FalseValue;
};

class CharObject : public Object {
private:
    char _value;

public:
    CharObject(char v);
    CharObject* add(CharObject* r);
    CharObject* sub(CharObject* r);
    char value() {
        return _value;
    }
    void print();
    Object* add(Object* o);
};

#endif
